package com.joymart.admin.rest;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.joymart.common.error.handling.JoymartBusinessException;
import com.joymart.common.model.Range;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.manual.operation.log.model.ManualOperationLog;
import com.joymart.manual.operation.log.service.ManualOperationLogService;
import com.joymart.product.model.Product;
import com.joymart.product.service.ProductService;
import com.joymart.product.service.StockService;
import lombok.Data;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import static org.springframework.util.StringUtils.hasText;


@RestController
@RequestMapping("/admin")
public class ProductAdminController {

    @Autowired
    private ProductService productService;
    @Autowired
    private StockService stockService;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private ManualOperationLogService manualOperationLogService;


    @GetMapping("/products")
    public List<?> getAll() {
        return productService.findAllNotDeletedProducts()
                .stream()
                .sorted(Comparator.nullsFirst(
                        Comparator.comparing(product -> ((Product) product).getMeta().optInt("weight"))
                                .reversed()
                ))
                .map(this::toProductWithStock)
                .toList();
    }


    @PostMapping("/products")
    public void createNewProduct(@RequestBody CreateParams createParams) {
        SecurityUtils.requiresRestAuthority("ProductRelated");
        createParams.validate();

        Product product = new Product();
        product.setMeta(new JSONObject());
        BeanUtils.copyProperties(createParams, product);
        product.setMeta(product.getMeta()
                .put("weight", createParams.getWeight())
                .put("imageUrl", createParams.getImageUrl())
                .put("originalPrice", createParams.getOriginalPrice())
                .put("detailImageUrl", createParams.getDetailImageUrl())
                .put("categories", createParams.getCategories())
                .put("treatmentEffect", createParams.getTreatmentEffect())
        );
        productService.create(product, createParams.getStock());
    }

    @PutMapping("/products/{id}")
    public void modifyProductBasics(@PathVariable String id, @RequestBody ModifyParams modifyParams) {
        SecurityUtils.requiresRestAuthority("ProductRelated");
        modifyParams.validate();

        Product existing = productService.findById(id);
        BeanUtils.copyProperties(modifyParams, existing);
        existing.setMeta(existing.getMeta()
                .put("weight", modifyParams.getWeight())
                .put("originalPrice", modifyParams.getOriginalPrice())
                .put("imageUrl", modifyParams.getImageUrl())
                .put("detailImageUrl", modifyParams.getDetailImageUrl())
                .put("categories", modifyParams.getCategories())
                .put("treatmentEffect", modifyParams.getTreatmentEffect()));
        productService.modify(existing);
    }

    /**
     * 上架下架
     *
     * @param id
     * @param action
     */
    @PutMapping("/products/{id}/status")
    public void modifyProductStatus(@PathVariable String id, @RequestParam String action) {
        SecurityUtils.requiresRestAuthority("ProductRelated");
        boolean target = action.equalsIgnoreCase("on");
        productService.changeStatus(id, target);
    }

    /**
     * 修改库存
     *
     * @param id
     * @param delta 变化量 整数
     */
    @PutMapping("/products/{id}/stock")
    public void modifyProductStock(@PathVariable String id, @RequestParam Integer delta) {
        SecurityUtils.requiresRestAuthority("ProductRelated");
        productService.adjustStock(id, delta);
        Map<String, Object> details = Map.of("delta", delta, "postStock", stockService.getCurrentStock(id));
        manualOperationLogService.insert("ADJUST_STOCK", id, details, SecurityUtils.getCurrentUserId());
    }


    @GetMapping("/products/stock/logs")
    public Page<ManualOperationLog> searchStockOperationLogs(
            @RequestParam(required = false) LocalDateTime start,
            @RequestParam(required = false) LocalDateTime end,
            @RequestParam(value = "pageNo", defaultValue = "0") Integer pageNo,
            @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize,
            @RequestParam(value = "operatorId", defaultValue = "") String operatorId,
            @RequestParam(value = "productId", defaultValue = "") String productId) {
        if (start == null) {
            start = DatetimeUtils.now().minusDays(7);
        }

        if (end == null) {
            end = DatetimeUtils.now();
        }
        Range range = Range.of(start, end);
        Pageable pageable = PageRequest.of(pageNo, pageSize);
        return manualOperationLogService.search(pageable, range, "ADJUST_STOCK", productId, operatorId);
    }


    private JSONObject toProductWithStock(Product product) {
        int currentStock = stockService.getCurrentStock(product.getId());
        return new JSONObject(objectMapper.convertValue(product, Map.class)).put("stock", currentStock);
    }

    @Data
    public static class ModifyParams {
        private String name;
        private String description;
        private String feedback;
        private String treatmentEffect;
        private List<String> categories;
        private String imageUrl;
        private String detailImageUrl;
        private BigDecimal price;
        private BigDecimal originalPrice;
        private Integer weight;
        private BigDecimal pv;

        public void validate() {
            if (price.intValue() <= 0) {
                throw new JoymartBusinessException("提交了错误单价");
            }
            if (pv.intValue() < 0) {
                throw new JoymartBusinessException("提交了错误积分");
            }
            if (!hasText(name)) {
                throw new JoymartBusinessException("提交了错误产品名");
            }
            if (!hasText(imageUrl)) {
                throw new JoymartBusinessException("主图片存在问题");
            }
            if (!hasText(detailImageUrl)) {
                throw new JoymartBusinessException("详情图片存在问题");
            }
        }
    }

    @Data
    public static class CreateParams {
        private String name;
        private String description;
        private String imageUrl;
        private String detailImageUrl;
        private String treatmentEffect;
        private List<String> categories;
        private BigDecimal price;
        private BigDecimal originalPrice;
        private String feedback;
        private BigDecimal pv;
        private Integer weight;
        private int stock;

        public void validate() {
            if (stock < 0) {
                throw new JoymartBusinessException("初始库存不正确");
            }

            if (price.intValue() <= 0) {
                throw new JoymartBusinessException("提交了错误单价");
            }

            if (pv.intValue() < 0) {
                throw new JoymartBusinessException("提交了错误积分");
            }

            if (!hasText(name)) {
                throw new JoymartBusinessException("提交了错误产品名");
            }

            if (!hasText(imageUrl)) {
                throw new JoymartBusinessException("主图片存在问题");
            }
            if (!hasText(detailImageUrl)) {
                throw new JoymartBusinessException("详情图片存在问题");
            }
        }
    }


}
